﻿using PMS.Core.Configuration.CommonEnumConfigs;
using PMS.Data.Entities;
using PMS.Data.Entities.Security;
using PMS.Services.EntityServices.Customers;
using PMS.Services.EntityServices.Security;
using PMS.Web.Framework.Models;
using PMS.Web.Models.Customers;
using System;
using System.Linq;

namespace PMS.Web.Factories.Customers
{
    /// <summary>
    /// Represents the base implementation of the factory of model which supports access control list (ACL)
    /// </summary>
    public partial class AclSupportedModelFactory : IAclSupportedModelFactory
    {
        #region Fields

        private readonly IAclService _aclService;
        private readonly ICustomerService _customerService;

        #endregion

        #region Ctor

        public AclSupportedModelFactory(IAclService aclService,
            ICustomerService customerService)
        {
            _aclService = aclService;
            _customerService = customerService;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Prepare selected and all available customer roles for the passed model
        /// </summary>
        /// <typeparam name="TModel">ACL supported model type</typeparam>
        /// <param name="model">Model</param>
        public virtual void PrepareModelCustomerRoles<TModel>(TModel model) where TModel : IAclSupportedModel
        {
            if (model == null)
                throw new ArgumentNullException(nameof(model));

            //prepare available customer roles
            var availableRoles = _customerService.GetAllCustomerRoles(showHidden: true);
            if(model is CustomerSearchModel)
            {
                model.AvailableCustomerRoles = availableRoles.Select(role => new XMSelectListItem
                {
                    Text = role.DisplayName,
                    Value = role.Id.ToString(),
                    Selected = model.SelectedCustomerRoleIds?.Contains(role.Id) ?? false
                }).ToList();
            } 
            else //if(model is CustomerModel)
            {
                RoleType[] roleTypes = new RoleType[] { RoleType.Guests, RoleType.BackendUser, RoleType.Administrator }; 
                model.AvailableCustomerRoles = availableRoles.Where(r => roleTypes.Contains(r.RoleType))
                    .Select(role => new XMSelectListItem
                {
                    Text = role.DisplayName,
                    Value = role.Id.ToString(),
                    Selected = model.SelectedCustomerRoleIds?.Contains(role.Id) ?? false
                }).ToList();
            }

        }

        /// <summary>
        /// Prepare selected and all available customer roles for the passed model by ACL mappings
        /// </summary>
        /// <typeparam name="TModel">ACL supported model type</typeparam>
        /// <typeparam name="TEntity">ACL supported entity type</typeparam>
        /// <param name="model">Model</param>
        /// <param name="entity">Entity</param>
        /// <param name="ignoreAclMappings">Whether to ignore existing ACL mappings</param>
        public virtual void PrepareModelCustomerRoles<TModel, TEntity>(TModel model, TEntity entity, bool ignoreAclMappings)
            where TModel : IAclSupportedModel where TEntity : BaseEntity, IAclSupported
        {
            if (model == null)
                throw new ArgumentNullException(nameof(model));

            //prepare customer roles with granted access
            if (!ignoreAclMappings && entity != null)
                model.SelectedCustomerRoleIds = _aclService.GetCustomerRoleIdsWithAccess(entity).ToList();

            PrepareModelCustomerRoles(model);
        }

        #endregion
    }

}
